#!/usr/bin/env python
#
# Copyright (C) 2011 Clement Lorteau <clem@lorteau.fr>	
#		
# This file is part of QuickScreenShots.		
# 	
# This program is free software; you can redistribute it and/or modify	
# it under the terms of the GNU General Public License as published by		
# the Free Software Foundation; version 3.	
# 	
# This program is distributed in the hope that it will be useful,		
# but WITHOUT ANY WARRANTY; without even the implied warranty of		
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the		
# GNU General Public License for more details.		
# 		
# You should have received a copy of the GNU General Public License		
# along with this program; if not, write to the Free Software		
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

import os
import re
import gzip
import urllib2
import StringIO
import platform
from datetime import datetime, timedelta
from __init__ import __version__

if platform.system() == 'Windows':
	conf_files_dir = os.path.join(os.getenv('APPDATA'), 'QuickScreenShots')
elif platform.system() == 'Darwin':
	conf_files_dir = os.path.join(os.getenv('HOME'), 'Library', 'Application Support',
								  'QuickScreenShots')
else:
	raise Exception('Unrecognized platform')
date_format = '%a, %d %b %Y %H:%m:%M'
download_page = 'http://code.google.com/p/quickscreenshots/downloads/list'

def __cmp_versions(a, b):
    """
    Compare 2 version numbers and return a cmp like value:
       -1 is a<b, 0 if a=b, 1 if a>b
    Source: http://bytes.com/topic/python/answers/43087-version-number-comparison-function#post164109
    """
    def fixup(i):
        try:
            return int(i)
        except ValueError:
            return i
    a = map(fixup, re.findall("\d+|\w+", a))
    b = map(fixup, re.findall("\d+|\w+", b))
    # while len(a) > len(b):
        # b.append(0)
    # while len(b) > len(a):
        # a.append(0)
    return cmp(a, b)
    
def __get_last_checked():
    """Retrieve the last time we successfully checked for an update"""
    save_file = 'last_update_check'
    try:
        file = open(os.path.join(conf_files_dir, save_file), 'r')
    except Exception, e:
        return None
    ret = file.read()
    file.close()
    return ret
    
def __set_last_checked():
    """Store the last time we successfully checked for an update"""
    now = datetime.now().strftime(date_format)
    save_file = 'last_update_check'
    if not os.path.exists(conf_files_dir):
            os.makedirs(conf_files_dir)
    file = open(os.path.join(conf_files_dir, save_file), 'w')
    file.write(now)
    file.close()
    
def __get_perm_redirect():
    """Retrieve a previously stored permanent redirect address"""
    save_file = 'redir'
    try:
        file = open(os.path.join(conf_files_dir, save_file), 'r')
    except Exception, e:
        return None
    ret = file.read()
    file.close()
    return ret
    return None
    
def __set_perm_redirect(url):
    """Store a permanent redirect address"""
    save_file = 'redir'
    if not os.path.exists(conf_files_dir):
            os.makedirs(conf_files_dir)
    file = open(os.path.join(conf_files_dir, save_file), 'w')
    file.write(now)
    file.close()
    pass
    
class DefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):    
    """http://diveintopython.org/http_web_services/etags.html"""
    def http_error_default(self, req, fp, code, msg, headers): 
        result = urllib2.HTTPError(                           
            req.get_full_url(), code, msg, headers, fp)       
        result.status = code                                   
        return result
    
class SmartRedirectHandler(urllib2.HTTPRedirectHandler):
    """http://diveintopython.org/http_web_services/redirects.html"""
    def http_error_301(self, req, fp, code, msg, headers):
        """Permanent redirect"""
        result = urllib2.HTTPRedirectHandler.http_error_301( 
            self, req, fp, code, msg, headers)              
        result.status = code                                 
        return result                                       

    def http_error_302(self, req, fp, code, msg, headers):
        """Temporary redirect"""
        result = urllib2.HTTPRedirectHandler.http_error_302(
            self, req, fp, code, msg, headers)              
        result.status = code                                
        return result   

def check_updates(now=False, debug=False):
    """
    Check if a new update is available, trying not to be too rude to the server hosting the project
    I'll make sure each release version number is composed only of digits, not letters
    
    return True if a new version exists, False otherwise
    """
    if debug:
        import httplib
        httplib.HTTPConnection.debuglevel = 1
        
    curver = __version__
    regexp = 'QuickScreenShots-(.+\d)\.zip\"'
    
    #try not to call an old address
    redir = __get_perm_redirect()
    if redir:
        request = urllib2.Request(redir)
    else:
        request = urllib2.Request(download_page)
    
    if not now:
        last_checked = __get_last_checked()
        if last_checked:
            #don't check for updates more than once a week
            last_checked_date = datetime.strptime(last_checked, date_format)
            delta = last_checked_date - datetime.now()
            eight_days = timedelta(8)
            if delta < eight_days:
                return False
            #try not to retrieve the page body if it was not modified since last time
            request.add_header('If-Modified-Since', last_checked)
    
    #go
    request.add_header('User-Agent',
                       'QuickScreenShots/%s +http://code.google.com/p/quickscreenshots/' % curver)
    request.add_header('Accept-encoding', 'gzip')
    opener = urllib2.build_opener(SmartRedirectHandler(), DefaultErrorHandler())
    result = opener.open(request)
    
    if hasattr(result, 'status'):
        if result.status == 301:
            __set_perm_redirect(result.url)
        if result.status == 304: #not modified since last time
            __set_last_checked()
            return False
        if result.status == 404:
            return False
    
    #read page and ungzip if needed
    body = result.read()
    if debug:
        print result.headers
    if result.headers.get('content-encoding', '') == 'gzip':
        result = gzip.GzipFile(fileobj=StringIO(result)).read()
        
    #parse        
    versions = re.findall(regexp, body)
    
    ret = False
    if debug:
        print versions
    for version in versions:
        if __cmp_versions(version, curver) == 1:
            ret = True
            break
    if not now:
        __set_last_checked()
    return ret
    
if __name__ == '__main__':
    print check_updates(True)